/***************************************************************************
 * 
 * Copyright (c) 2012 Baidu.com, Inc. All Rights Reserved
 * common.h,v 1.0 2012-08-17 11:30 yelu01 
 * 
 **************************************************************************/
 
 
 
/**
 * @file disk_matrix.h
 * @author yelu01(yelu01@baidu.com)
 * @date 2012-08-17 11:30
 * @version 1.0 
 * @brief matrix operation on disk using sorted string table.
 *  
 **/

#pragma once

#include <cstdio>
#include <stdint.h>
#include <boost/shared_ptr.hpp>
#include "item.h"
#include "iterator.h"
#include "bloom_filter.h"
#include "cache.h"
#include "bytes.h"
#include "log.h"
#include "check_macro.h"

struct data_block_t:public cachable_t
{
	static const uint32_t magic;
	std::vector<pitem> items;
	uint64_t bytes_cnt;		// no persistence, used for cache memory estimate.
	data_block_t();
	~data_block_t();
	uint64_t bytes();
	int add_item(const pitem& item);
	uint64_t serialize(FILE* fp);
	uint64_t deserialize(FILE* fp);
};
typedef boost::shared_ptr<data_block_t> pdata_block;

struct index_t
{
	bytes_t last_key;
	uint64_t offset;
	//uint64_t data_block_size;
	uint64_t serialize(FILE* fp);
	uint64_t deserialize(FILE* fp);
};
typedef boost::shared_ptr<index_t> pindex;

// index block. always in memory.
struct index_block_t
{
	static const uint32_t magic;
	std::vector<pindex> indexes;
	index_block_t();
	~index_block_t();
	int add_index(const pindex& index);
	uint64_t serialize(FILE* fp);
	uint64_t deserialize(FILE* fp);
};
typedef boost::shared_ptr<index_block_t> pindex_block;

// summary block. always in memory.
struct summary_t
{
	static const uint32_t magic;
	uint64_t index_block_offset;
	uint64_t total_item_num;
	bytes_t first_key;				// used for binary search and key existence
									// check.
	bytes_t last_key;
	bloom_filter_t bloom_filter;	// for fast key existence check.
	uint64_t summary_offset;		// for locating the summary info block.
									// no persistence.
	uint64_t serialize(FILE* fp);
	uint64_t deserialize(FILE* fp);
};

class disk_matrix_iterator_t;
// Cache type used by file_map_t.
typedef boost::shared_ptr<cache_t> pcache;

class disk_matrix_t
{
public:

	disk_matrix_t(const char* file_path,
			const pcache& cache,
			comparator row_cmp = bytes_t::raw_comparator,
			comparator col_cmp = bytes_t::raw_comparator);

	~disk_matrix_t();

	// create a file_map_t
	int create();

	// load file map;
	int load();

	// find an item by index_key.
	int find(const bytes_t& row, std::vector<pitem>& res);

	// save sorted item_t vector to disk matrix.
	int save(iterator_t& ite);

	friend class disk_matrix_iterator_t;

private:
	// binary search index_key in index_block and by bloom filter.
	int _bsearch_index_block(const index_block_t& index_block,
							 const bytes_t& target, uint64_t& offset);
	int _bsearch_data_block(const pdata_block& data_block,
			 	 	 	 	const bytes_t& target,
			 	 	 	 	std::vector<pitem>& res);
	char file_path[1024];
	index_block_t index_block;
	summary_t summary;
	pcache cache;	    			// used for cache data block; multiple file_map_t
									// may share a cache. so file_map_t is not
									// resposilble for creating and destroy cache.
	comparator row_cmp;				// used to compare index keys.
	comparator col_cmp;				// used to compare extra keys.
	uint64_t cache_id;				// a cacheid corresponding to a file.
	static const uint64_t data_block_size = 65536;	// 64kB data block.
	static uint64_t cache_id_seed;	//TODO. Remember to add lock when needed.
};

class disk_matrix_iterator_t:public iterator_t
{
public:

	disk_matrix_iterator_t(disk_matrix_t& disk_matrix);

	int reset();

	int get_next(pitem& item);

	uint64_t size();

private:

	disk_matrix_t& _disk_matrix;
	pdata_block _data_block;
	index_block_t& _index_block;	// This is shared with file_map obj, we
										// give up using smart ptr because using
										// smart ptr will cause a problem.
	uint64_t _index_in_data_block;
	uint64_t _index_in_index_block;
	bool _is_reset;
};



//YFile* loading_yfile(char* file_path);

//public YFile* create_new_yfile(char* file_path, ResultSet* resultSet, char* table_name);

//public ResultSet* query_yfile_by_row_key(YFile* yfile, char* row_key);

//public ResultSet* query_yfile_by_timestamp(YFile* yfile, long long begin_timestamp, long long end_timestamp);

//public void refresh_yfile_data_block_cache(YFile* yfile, int hotness_value);

//public char* get_yfile_metadata(YFile* yfile);


